/***********************************************************************************
Copy right:	    hqyj Tech.
Author:         jiaoyue
Date:           2023.07.01
Description:    http请求处理
***********************************************************************************/

#include <sys/types.h>
#include <sys/socket.h>
#include "custom_handle.h"

#define KB 1024
#define HTML_SIZE (64 * KB)

//普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"

struct shm_param para;

static int handle_login(int sock, const char *input)
{
    char reply_buf[HTML_SIZE] = {0};
    char *uname = strstr(input, "username=");
    uname += strlen("username=");
    char *p = strstr(input, "password");
    *(p - 1) = '\0';
    printf("username = %s\n", uname);

    char *passwd = p + strlen("password=");
    printf("passwd = %s\n", passwd);

    if (strcmp(uname, "admin") == 0 && strcmp(passwd, "admin") == 0)
    {
        sprintf(reply_buf, "<script>localStorage.setItem('usr_user_name', '%s');</script>", uname);
        strcat(reply_buf, "<script>window.location.href = '/index.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }
    else
    {
        printf("web login failed\n");

        //"用户名或密码错误"提示，chrome浏览器直接输送utf-8字符流乱码，没有找到太好解决方案，先过渡
        char out[128] = {0xd3, 0xc3, 0xbb, 0xa7, 0xc3, 0xfb, 0xbb, 0xf2, 0xc3, 0xdc, 0xc2, 0xeb, 0xb4, 0xed, 0xce, 0xf3};
        sprintf(reply_buf, "<script charset='gb2312'>alert('%s');</script>", out);
        strcat(reply_buf, "<script>window.location.href = '/login.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }

    return 0;
}
//如果web端发过来的type = 3,就执行发送请求，接受到web端传来的json进行反序列化，然后发给底层modbus
//然后底层读保持寄存器，从共享内存获取消息，发送到页面上页面显示。
static int getweb(int sock, cJSON *root)
{
    //从共享内存中取出对应的数据发送到网页上
    //第一行的四个字节
    int *total;
    //各个结构体大小
    struct std_node *node_arr;
    //获取共享内存地址
    void *node_p = shm_getaddr(&para);
    if (NULL == node_p)
    {
        return -1;
    }

    //开始偏移
    total = (int *)node_p;
    node_arr = (struct std_node *)(node_p + sizeof(int));

    //序列化发送
    cJSON *gen = cJSON_CreateObject();
    //进入到此时type==3
    cJSON *number = cJSON_CreateNumber(3);
    //{"type" = 3}
    cJSON_AddItemToObject(gen, "type", number);
    //打印一下序列化后的type
    // char *p = cJSON_PrintUnformatted(gen);
    // printf("gen:%s\n", p);

    //从发过来的数据中找到定义的key
    cJSON *keys = cJSON_GetObjectItem(root, "key");
    int size = cJSON_GetArraySize(keys);

    char typevalue[15];
    //拿出来size，进行循环
    printf("size:%d\n", size);
    //key挂上
    cJSON *arr = cJSON_CreateArray();
    for (int i = 0; i < size; i++)
    {
        cJSON *key = cJSON_GetArrayItem(keys, i);
        //得到的数是 3 和 4，对应点表的key，相等即执行相应的的代码
        printf("valueint:%d\n", key->valueint);
        //遍历共享内存中所有的表
        for (int j = 0; j < *total; j++)
        {
            if (node_arr[j].key == key->valueint)
            {
                //创建对象
                cJSON *son = cJSON_CreateObject();
                memset(typevalue, 0, sizeof(typevalue));
                //获得可以进入判断的key->value
                cJSON *number1 = cJSON_CreateNumber(key->valueint);
                //先把key挂树上
                cJSON_AddItemToObject(son, "key", number1);

                if (node_arr[j].type == 2)
                {
                    sprintf(typevalue, "%d", node_arr[j].new_val.i_val);
                }
                else if (node_arr[j].type == 3)
                {
                    //如果type是3就去取出float值，也就是温室度
                    sprintf(typevalue, "%.2f", node_arr[j].new_val.f_val);
                }
                else if (node_arr[j].type == 1)
                {
                    //如果type是1,就取出boolen值，也就是控制设备
                    sprintf(typevalue, "%d", node_arr[j].new_val.b_val);
                }
                cJSON *val = cJSON_CreateString(typevalue);
                cJSON_AddItemToObject(son, "val", val);
                cJSON_AddItemToArray(arr, son);
                break;
            }
        }
    }

    //序列化发给web
    cJSON_AddItemToObject(gen, "data", arr);
    char *p = cJSON_PrintUnformatted(gen);
    printf("发给web的数据是%s\n", p);
    send(sock, p, strlen(p), 0);

    free(p);
    p = NULL;
    cJSON_Delete(root);
    cJSON_Delete(gen);
    //然后去判断这个key是否能与自己的共享内存key相等，相等即执行对应的操作
}

//如果web断发过来的type = 1,就执行操作请求，通过消息队列，发送给modbessever控制底层
static int setweb(int sock, cJSON *root, const char *input)
{
    struct msgbuf send_buf;

    //从共享内存中取出对应的数据发送到网页上
    //第一行的四个字节
    int *total;
    //各个结构体大小
    struct std_node *node_arr;
    //获取共享内存地址
    void *node_p = shm_getaddr(&para);
    if (NULL == node_p)
    {
        return -1;
    }

    //开始偏移
    total = (int *)node_p;
    node_arr = (struct std_node *)(node_p + sizeof(int));
    printf("1\n");
    //获取从网页发过来的key
    cJSON *keys = cJSON_GetObjectItem(root, "key");
    
    for (int i = 0; i < *total; i++)
    {
        if (node_arr[i].key == keys->valueint)
        {
            send_buf.mtype = node_arr[i].dev_type;
            break;
        }
    }
    char *p = cJSON_PrintUnformatted(root);
    
    strncpy(send_buf.mdata, p, strlen(p));
    printf("111%s\n",send_buf.mdata);
    if (msg_queue_send("topic", &send_buf, sizeof(send_buf),0) < 0)
    {
        printf("msg_queue_send error\n");
        return -1;
    }
    printf("这里是发给msg的：%s\n",p);
    printf("2\n");
    printf("-------111");
    free(p);
    p = NULL;
    cJSON_Delete(root);
}

/**
 * @brief 处理自定义请求，在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    //query_string不一定能用的到

    //先处理登录操作
    if (strstr(input, "username=") && strstr(input, "password="))
    {
        printf("%s", input);
        return handle_login(sock, input);
    }
    else //剩下的都是json请求，这个和协议有关了
    {
        cJSON *root = cJSON_Parse(input);
        //反序列
        cJSON *type = cJSON_GetObjectItem(root, "type");
        // char *p = cJSON_PrintUnformatted(root);
        // printf("web:%s\n",p);
        printf("valueinttype:%d\n",type->valueint);
        if (type->valueint == 3)
        {
            getweb(sock, root);
        }
        else if (type->valueint == 1)
        {
            setweb(sock, root, input);
        }
    }

    return 0;
}
